home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / mac / maccmd.c < prev    next >
Text File  |  1995-05-02  |  22KB  |  1,187 lines

  1. /* Commands for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10. #include "print.h"
  11. #include "macconq.h"
  12. extern WindowPtr playersetupwin;
  13.  
  14. #undef DEF_CMD
  15. #define DEF_CMD(letter,name,args,FN,help) extern void FN(void);
  16.  
  17. #include "cmd.def"
  18.  
  19. #include "maccmd.def"
  20.  
  21. extern int do_one_give(Unit *unit);
  22. extern int do_one_take(Unit *unit);
  23. extern int do_one_return(Unit *unit);
  24. extern int do_one_detonate(Unit *unit);
  25. extern int do_one_give_unit(Unit *unit);
  26. static int do_one_delay(Unit *unit);
  27. extern int do_one_detach(Unit *unit);
  28. extern int do_one_disband(Unit *unit);
  29.  
  30. static int do_one_reserve(Unit *unit);
  31. static int do_one_asleep(Unit *unit);
  32. static int do_one_ai_control(Unit *unit);
  33.  
  34. extern int do_one_clear_plan(Unit *unit);
  35. extern int do_one_dir_move(Unit *unit);
  36. extern int do_one_dir_multiple_move(Unit *unit);
  37. extern int do_one_set_name(Unit *unit);
  38.  
  39. static int do_one_add_terrain(Unit *unit);
  40. static int do_one_remove_terrain(Unit *unit);
  41.  
  42. static void resign_the_game(int forced);
  43.  
  44. extern int forcedtoresign;
  45.  
  46. extern int modal_construction;
  47.  
  48. extern WindowPtr window_behind_construction;
  49.  
  50. extern Feature *featurelist;
  51.  
  52. #ifdef THINK_C
  53. #include <profile.h>
  54. #endif
  55.  
  56. extern int Profile;
  57.  
  58. #ifdef PROFILING
  59. extern int _trace;
  60. #endif
  61.  
  62. #define side_may_select(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
  63.  
  64. #define valid_selection(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))
  65.  
  66. extern int gamestatesafe;
  67. extern int interfacestatesafe;
  68.  
  69. extern char *cursavename;
  70.  
  71. /* Static (local) variables. */
  72.  
  73. static int tmpcmdarg;
  74. static int tmprecurse;
  75.  
  76. static int tmpcmdx, tmpcmdy, tmpcmddir;
  77.  
  78. /* This is the actual key typed, for use if several keyboard commands
  79.    share a single function. */
  80.  
  81. static char tmpkey;
  82.  
  83. /* Prefixed numeric argument to commands. */
  84.  
  85. static int prefixarg;
  86.  
  87. static int tmpdir;
  88.  
  89. static int tmpargc;
  90.  
  91. static char **tmpargv;
  92.  
  93. /* This flag is set to prevent running an "other" command when already
  94.    executing an "other" command. */
  95.  
  96. static int doingother = FALSE;
  97.  
  98. typedef struct cmdtab {
  99.     char fchar;                 /* character to match against */
  100.     char *name;                 /* full name of command */
  101.     void (*fn)(void);           /* pointer to command's function */
  102.     char *help;                 /* short documentation string */
  103. } CmdTab;
  104.  
  105. #define C(c) ((c)-0x40)
  106.  
  107. #undef DEF_CMD
  108. #define DEF_CMD(LETTER,NAME,args,FN,HELP) { LETTER, NAME, FN, HELP },
  109.  
  110. /* The generic command table. */
  111.  
  112. CmdTab commands[] = {
  113.  
  114. #include "maccmd.def"
  115.  
  116. #include "cmd.def"
  117.  
  118.   { 0, NULL, NULL, NULL }
  119. };
  120.  
  121. /* The Mac-specific command table. */
  122.  
  123. CmdTab mac_commands[] = {
  124.  
  125. #include "maccmd.def"
  126.  
  127.   { 0, NULL, NULL, NULL }
  128. };
  129.  
  130. /* Given a character, find a command for it and execute. */
  131.  
  132. void
  133. do_keyboard_command(int key)
  134. {
  135.     CmdTab *cmd;
  136.     void (*fn)(void);
  137.  
  138.     DGprintf("Typed '%c' (0x%x)\n", key, key);
  139.     if (between('0', key, '9')) {
  140.         /* Add a decimal digit to the prefix argument. */
  141.         if (prefixarg < 0) prefixarg = 0;
  142.         prefixarg += prefixarg * 10 + (key - '0');
  143.         /* (should add some sort of feedback) */
  144.     } else {
  145.         /* Look through the generic command table. */
  146.         for (cmd = commands; cmd->name != NULL; ++cmd) {
  147.             if (key == cmd->fchar) {
  148.                 if ((fn = cmd->fn) == NULL) {
  149.                     run_warning("no command function for %s (0x%x)?", cmd->name, key);
  150.                     return;
  151.                 }
  152.                 tmpkey = key;
  153.                 (*fn)();
  154.                 /* Reset the prefix argument. */
  155.                 prefixarg = -1;
  156.                 return;
  157.             }
  158.         }
  159.     }
  160. }
  161.  
  162. void
  163. execute_named_command(char *cmdstr)
  164. {
  165.     char *cmdname = NULL;
  166.     CmdTab *cmd;
  167.     int i;
  168.     void (*fn)(void);
  169.  
  170.     tmpargc = 0;
  171.     if (tmpargv == NULL)
  172.       tmpargv = (char **) xmalloc(2 * sizeof(char *));
  173.     if (strchr(cmdstr, ' ')) {
  174.         for (i = 0; cmdstr[i] != ' ' && cmdstr[i] != '\0'; ++i);
  175.         cmdname = cmdstr + i;
  176.     } else {
  177.         cmdname = cmdstr;
  178.     }
  179.     if (cmdname == NULL || *cmdname == '\0') return;
  180.     tmpargv[tmpargc++] = cmdname;
  181.     for (cmd = commands; cmd->name != NULL; ++cmd) {
  182.         if (strcmp(cmdname, cmd->name) == 0) {
  183.             if ((fn = cmd->fn) == NULL) {
  184.                 run_warning("no command function for %s?", cmd->name);
  185.                 return;
  186.             }
  187.             /* Use the command's char as the apparent key. */
  188.             tmpkey = cmd->fchar;
  189.             (*fn)();
  190.             /* Reset the prefix argument. */
  191.             prefixarg = -1;
  192.             return;
  193.         }
  194.     }
  195.     beep();
  196. }
  197.  
  198. void
  199. describe_commands(int arg, char *key, char *buf)
  200. {
  201.     describe_command_table(arg, key, buf, commands);
  202.     /* (should split out Mac-specific commands??) */
  203. }
  204.  
  205. void
  206. describe_command_table(int arg, char *key, char *buf, CmdTab *cmdtab)
  207. {
  208.     CmdTab *cmd;
  209.  
  210.     strcat(buf, "Single-key commands:\n\n");
  211.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  212.         describe_command(cmd->fchar, cmd->name, cmd->help, TRUE, buf);
  213.     }
  214.     strcat(buf, "\nLong name commands:\n\n");
  215.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  216.         describe_command (cmd->fchar, cmd->name, cmd->help, FALSE, buf);
  217.     }
  218. }
  219.  
  220. /* Start of alphabetized commands. */
  221.  
  222. void
  223. do_add_player()
  224. {
  225.     beep();
  226. }
  227.  
  228. void
  229. do_add_terrain()
  230. {
  231.     int x, y, dir;
  232.     Point to;
  233.     Map *map;
  234.     
  235.     if ((map = map_from_window(FrontWindow())) != NULL) {
  236.         GetMouse(&to);
  237.         if (m_nearest_boundary(map, to.h, to.v, &x, &y, &dir)) {
  238.             tmpcmdx = x;  tmpcmdy = y;  tmpcmddir = dir;
  239.             apply_to_all_selected(do_one_add_terrain, TRUE);
  240.             return;
  241.         }
  242.     }
  243.     beep();
  244. }
  245.  
  246. static int
  247. do_one_add_terrain(Unit *unit)
  248. {
  249.     int u, t, dir;
  250.  
  251.     u = unit->type;
  252.     for_all_terrain_types(t) {
  253.         if (ut_acp_to_add_terrain(u, t) > 0
  254.             && unit->act
  255.             && unit->act->acp >= ut_acp_to_add_terrain(u, t)) {
  256.             if (distance(tmpcmdx, tmpcmdy, unit->x, unit->y) <= ut_alter_range(u, t)) {
  257.                 if (prep_add_terrain_action(unit, unit, tmpcmdx, tmpcmdy, tmpcmddir, t))
  258.                   return TRUE;
  259.             } else {
  260.                 dir = closest_dir(tmpcmdx - unit->x, tmpcmdy - unit->y);
  261.                 if (prep_add_terrain_action(unit, unit, unit->x, unit->y, dir, t))
  262.                   return TRUE;
  263.             }
  264.         }
  265.     }
  266.     return FALSE;
  267. }
  268.  
  269. void
  270. do_ai_side()
  271. {
  272.     if (side_has_ai(dside)) {
  273.         set_side_ai(dside, NULL);
  274.     } else {
  275.         set_side_ai(dside, "mplayer");
  276.     }
  277. }
  278.  
  279. void
  280. do_attack()
  281. {
  282.     do_attack_command();
  283. }
  284.  
  285. void
  286. do_auto()
  287. {
  288.     do_ai_control_command();
  289. }
  290.  
  291. int favored_type(Unit *unit);
  292.  
  293. void
  294. do_build()
  295. {
  296.     int i;
  297.     Map *map;  List *list;  UnitCloseup *closeup;
  298.     Unit *unit;
  299.     
  300.     if ((map = map_from_window(FrontWindow())) != NULL) {
  301.         for (i = 0; i < map->numselections; ++i) {
  302.             if ((unit = map->selections[i]) != NULL) {
  303.                 if (can_build(unit)) {  /* and completers and researchers too? */
  304.                     modal_construction = TRUE;
  305.                     window_behind_construction = FrontWindow();
  306.                     enable_construction();
  307.                     select_unit_in_construction_window(unit);
  308.                     select_type_in_construction_window(favored_type(unit));
  309.                     return;
  310.                 }
  311.             }
  312.         }
  313.     } else if ((list = list_from_window(FrontWindow())) != NULL) {
  314.         if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
  315.                 if (can_build(unit)) {  /* and completers and researchers too? */
  316.                     modal_construction = TRUE;
  317.                     enable_construction();
  318.                     select_unit_in_construction_window(unit);
  319.                     select_type_in_construction_window(favored_type(unit));
  320.                     return;
  321.                 }
  322.         }
  323.     } else if ((closeup = unit_closeup_from_window(FrontWindow())) != NULL) {
  324.         if ((unit = closeup->unit) != NULL) {
  325.                 if (can_build(unit)) {  /* and completers and researchers too? */
  326.                     modal_construction = TRUE;
  327.                     enable_construction();
  328.                     select_unit_in_construction_window(unit);
  329.                     select_type_in_construction_window(favored_type(unit));
  330.                     return;
  331.                 }
  332.         }
  333.     }
  334. }
  335.  
  336. /* (should be in kernel?) */
  337.  
  338. int
  339. favored_type(Unit *unit)
  340. {
  341.     int u;
  342.  
  343.     if (unit == NULL)
  344.       return NONUTYPE;
  345.     if (unit->plan
  346.         && unit->plan->tasks
  347.         && unit->plan->tasks->type == TASK_BUILD)
  348.       return unit->plan->tasks->args[0];
  349.     for_all_unit_types(u) {
  350.         if (uu_acp_to_create(unit->type, u) > 0)
  351.           return u;
  352.     }
  353.     return NONUTYPE;
  354. }
  355.  
  356.  
  357. /* Create and/or bring up the construction planning window. */
  358.  
  359. void
  360. enable_construction()
  361. {
  362.     window_behind_construction = FrontWindow();
  363.     if (constructionwin == nil) {
  364.         create_construction_window();
  365.     }
  366.     if (constructionwin != nil) {
  367.         reinit_construction_lists();
  368.         ShowWindow(constructionwin);
  369.         SelectWindow(constructionwin);
  370.     }
  371. }
  372.  
  373. int
  374. do_one_clear_plan(Unit *unit)
  375. {
  376.     if (unit->plan) {
  377.         set_unit_plan_type(dside, unit, PLAN_NONE);
  378.         return TRUE;
  379.     }
  380.     return FALSE;
  381. }
  382.  
  383. void
  384. do_clear_plan()
  385. {
  386.     apply_to_all_selected(do_one_clear_plan, TRUE);    
  387. }
  388.  
  389. void
  390. do_copying()
  391. {
  392.     /* (should be a help node?) */
  393.     beep();
  394. }
  395.  
  396. void
  397. do_delay()
  398. {
  399.     apply_to_all_selected(do_one_delay, TRUE);
  400. }
  401.  
  402. int
  403. do_one_delay(Unit *unit)
  404. {
  405.     if (unit->plan) {
  406.         delay_unit(unit, TRUE);
  407.         return TRUE;
  408.     }
  409.     return FALSE;
  410. }
  411.  
  412. void
  413. do_detach()
  414. {
  415.     apply_to_all_selected(do_one_detach, TRUE);
  416. }
  417.  
  418. int
  419. do_one_detach(Unit *unit)
  420. {
  421.     if (!completed(unit)) {
  422.         return FALSE;
  423.     } else if (unit->act && unit->act->acp > 0) {
  424.         prep_transfer_part_action(unit, unit, unit->hp / 2, NULL);
  425.         return TRUE;
  426.     } else {
  427.         /* try to find a nearby unit to do it */
  428.     }
  429.     return FALSE;
  430. }
  431.  
  432. void
  433. do_detonate()
  434. {
  435.     do_detonate_command();
  436. }
  437.  
  438. /* Command all selected mobile units to move in a given direction. */
  439.  
  440. /* The function that gets called on each selected unit. */
  441.  
  442. int
  443. do_one_dir_move(Unit *unit)
  444. {
  445.     if (mobile(unit->type)) {
  446.         set_movedir_task(unit, tmpdir, 1);
  447.         return TRUE;
  448.     }
  449.     return FALSE;
  450. }
  451.  
  452. /* The command function proper. */
  453.  
  454. void
  455. do_dir()
  456. {
  457.     char *rawdir;
  458.     Map *map;
  459.  
  460.     if ((map = map_from_window(FrontWindow())) != NULL) {
  461.         rawdir = strchr(dirchars, tmpkey);
  462.         if (rawdir)
  463.           tmpdir = rawdir - dirchars;
  464.         else if (tmpkey == 'k')
  465.           tmpdir = (flip_coin() ? NORTHEAST : NORTHWEST);
  466.         else if (tmpkey == 'j')
  467.           tmpdir = (flip_coin() ? SOUTHEAST : SOUTHWEST);
  468.         else {
  469.             beep();
  470.             return;
  471.         }
  472.         apply_to_all_selected(do_one_dir_move, TRUE);
  473.     }
  474. }
  475.  
  476. /* Command all selected mobile units to move in a given direction. */
  477.  
  478. /* The function that gets called on each selected unit. */
  479.  
  480. int
  481. do_one_dir_multiple_move(Unit *unit)
  482. {
  483.     if (mobile(unit->type)) {
  484.         set_movedir_task(unit, tmpdir, 9999);
  485.         return TRUE;
  486.     }
  487.     return FALSE;
  488. }
  489.  
  490. /* The command function proper. */
  491.  
  492. void
  493. do_dir_multiple()
  494. {
  495.     char *rawdir;
  496.     Map *map;
  497.  
  498.     if ((map = map_from_window(FrontWindow())) != NULL) {
  499.         rawdir = strchr(dirchars, tolower(tmpkey));
  500.         if (rawdir)
  501.           tmpdir = rawdir - dirchars;
  502.         else if (tmpkey == 'k')
  503.           tmpdir = (flip_coin() ? NORTHEAST : NORTHWEST);
  504.         else if (tmpkey == 'j')
  505.           tmpdir = (flip_coin() ? SOUTHEAST : SOUTHWEST);
  506.         else {
  507.             beep();
  508.             return;
  509.         }
  510.         apply_to_all_selected(do_one_dir_multiple_move, TRUE);
  511.     }
  512. }
  513.  
  514. void
  515. do_disband()
  516. {
  517.     apply_to_all_selected(do_one_disband, TRUE);
  518. }
  519.  
  520. int
  521. do_one_disband(Unit *unit)
  522. {
  523.     /* (should call a designer_disband routine) */
  524. #ifdef DESIGNERS
  525.     if (dside->designer) {
  526.         kill_unit(unit, -1);
  527.         return TRUE;
  528.     } else
  529. #endif /* DESIGNERS */
  530.     if (!completed(unit)) {
  531.         kill_unit(unit, H_UNIT_DISBANDED);
  532.         return TRUE;
  533.     } else if (unit->act && unit->act->acp > 0) {
  534.         prep_disband_action(unit, unit);
  535.         return TRUE;
  536.     } else {
  537.         /* try to find a nearby unit to do it */
  538.     }
  539.     return FALSE;
  540. }
  541.  
  542. void
  543. do_distance()
  544. {
  545.     beep();
  546. }
  547.  
  548. void
  549. do_end_turn()
  550. {
  551.     /* <return> is also interpreted by dialogs, so special-case this, depending
  552.        on which window was in front. */
  553.     if (FrontWindow() == constructionwin) {
  554.         Point pt;
  555.         extern ControlHandle constructbutton;
  556.         
  557.         pt.h = (*constructbutton)->contrlRect.left + 8;
  558.         pt.v = (*constructbutton)->contrlRect.top + 8;
  559.         do_mouse_down_construction(pt, 0);
  560.     } else {
  561.         finish_turn(dside);
  562.     }
  563. }
  564.  
  565. void
  566. do_fire()
  567. {
  568.     do_fire_command();
  569. }
  570.  
  571. void
  572. do_fire_into()
  573. {
  574.     do_fire_into_command();
  575. }
  576.  
  577. void
  578. do_give()
  579. {
  580.     /* (should use argument) */
  581.     apply_to_all_selected(do_one_give, TRUE);
  582. }
  583.  
  584. void
  585. do_give_unit()
  586. {
  587.     int sn = 0;
  588.     Side *side;
  589.  
  590.     side = side_n(sn);
  591.     apply_to_all_selected(do_one_give_unit, TRUE);
  592. }
  593.  
  594. void
  595. do_help()
  596. {
  597.     help_dialog();
  598. }
  599.  
  600. void
  601. do_message()
  602. {
  603.     message_dialog();
  604. }
  605.  
  606. /* Dialog for the input of a textual message. */
  607.  
  608. /* (should add way to specify which sides to receive this) */
  609.  
  610. void
  611. message_dialog()
  612. {
  613.     short done = FALSE, ditem;
  614.     char *msg = NULL;
  615.     DialogPtr win;
  616.     short itemtype;  Handle itemhandle;  Rect itemrect;
  617.  
  618.     win = GetNewDialog(dMessage, NULL, (DialogPtr) -1L);
  619.     ShowWindow(win);
  620.     while (!done) {
  621.         draw_default_button(win, diMessageOK);
  622.         SetCursor(&QD(arrow));
  623.         ModalDialog(NULL, &ditem);
  624.         switch (ditem) {
  625.             case diMessageOK:
  626.                 GetDItem(win, diMessageText, &itemtype, &itemhandle, &itemrect);
  627.                 msg = get_string_from_item(itemhandle);
  628.                 /* Fall into next case. */
  629.             case diMessageCancel:
  630.                 done = TRUE;
  631.                 break;
  632.         }
  633.     }
  634.     /* Close down the dialog (*before* executing any command). */
  635.     DisposDialog(win);
  636.     /* Now send the message (if it wasn't cancelled) */
  637.     if (msg != NULL) {
  638.         send_message(dside, ALLSIDES, msg);
  639.     }
  640. }
  641.  
  642. void
  643. do_move_to()
  644. {
  645.     beep();
  646. }
  647.  
  648. int
  649. do_one_set_name(Unit *unit)
  650. {
  651.     return unit_rename_dialog(unit);
  652. }
  653.  
  654. void
  655. do_name()
  656. {
  657.     apply_to_all_selected(do_one_set_name, TRUE);
  658. }
  659.  
  660. void
  661. do_other()
  662. {
  663.     /* Don't allow recursion with this command. */
  664.     if (!doingother) {
  665.         doingother = TRUE;
  666.         command_dialog();
  667.         doingother = FALSE;
  668.     } else {
  669.         beep();
  670.     }
  671. }
  672.  
  673. /* Dialog for the input of a textual command. */
  674.  
  675. void
  676. command_dialog()
  677. {
  678.     short done = FALSE, ditem;
  679.     char *cmd = NULL;
  680.     DialogPtr win;
  681.     short itemtype;  Handle itemhandle;  Rect itemrect;
  682.  
  683.     win = GetNewDialog(dCommand, NULL, (DialogPtr) -1L);
  684.     ShowWindow(win);
  685.     while (!done) {
  686.         draw_default_button(win, diCommandOK);
  687.         SetCursor(&QD(arrow));
  688.         ModalDialog(NULL, &ditem);
  689.         switch (ditem) {
  690.             case diCommandOK:
  691.                 GetDItem(win, diCommandText, &itemtype, &itemhandle, &itemrect);
  692.                 cmd = get_string_from_item(itemhandle);
  693.                 /* Fall into next case. */
  694.             case diCommandCancel:
  695.                 done = TRUE;
  696.                 break;
  697.         }
  698.     }
  699.     /* Close down the dialog (*before* executing any command). */
  700.     DisposDialog(win);
  701.     /* Now do the command (if it wasn't cancelled) */
  702.     if (cmd != NULL) {
  703.         execute_named_command(cmd);
  704.     }
  705. }
  706.  
  707. void
  708. do_print_view()
  709. {
  710.     dump_ps_view(dside, NULL, "View PS");
  711. }
  712.  
  713. void
  714. do_produce()
  715. {
  716.     beep();
  717. }
  718.  
  719. void
  720. do_quit()
  721. {
  722.     quit_the_game();
  723. }
  724.  
  725. static int allsumx, allsumy, unitcount;
  726.  
  727. static int
  728. add_unit_position(Unit *unit)
  729. {
  730.     allsumx += unit->x;  allsumy += unit->y;
  731.     ++unitcount;
  732.     return TRUE;
  733. }
  734.  
  735. void
  736. do_recenter()
  737. {
  738.     int avgx, avgy;
  739.     Map *map;
  740.  
  741.     map = map_from_window(FrontWindow());
  742.     if (map != NULL) {
  743.         allsumx = allsumy = 0;
  744.         unitcount = 0;
  745.         apply_to_all_selected(add_unit_position, FALSE);
  746.         if (unitcount == 0) {
  747.             beep();
  748.             return;
  749.         }
  750.         avgx = allsumx / unitcount;  avgy = allsumy / unitcount;
  751.         set_focus(map, avgx, avgy);
  752.     }
  753. }
  754.  
  755. void
  756. set_focus(Map *map, int x, int y)
  757. {
  758.     if (!inside_area(x, y))
  759.       return;
  760.     set_view_focus(map->vp, x, y);
  761.     m_center_on_focus(map);
  762.     set_map_scrollbars(map);
  763.     force_map_update(map);
  764. }
  765.  
  766. /* Recalculate and redraw everything. */
  767.  
  768. void
  769. do_refresh()
  770. {
  771.     Map *map;
  772.     List *list;
  773.     UnitCloseup *closeup;
  774.  
  775.     reset_coverage();
  776.     reset_all_views();
  777.     compute_all_feature_centroids();
  778.     /* Force updates to all open windows. */
  779.     for_all_maps(map) {
  780.         force_update(map->window);
  781.     }
  782.     for_all_lists(list) {
  783.         force_update(list->window);
  784.     }
  785.     for_all_unit_closeups(closeup) {
  786.         force_update(closeup->window);
  787.     }
  788.     if (gamewin != nil) {
  789.         force_update(gamewin);
  790.     }
  791.     if (historywin != nil) {
  792.         force_update(historywin);
  793.     }
  794.     if (constructionwin != nil) {
  795.         force_update(constructionwin);
  796.     }
  797.     if (helpwin != nil) {
  798.         force_update(helpwin);
  799.     }
  800. }
  801.  
  802. void
  803. do_remove_terrain()
  804. {
  805.     int x, y, dir;
  806.     Point to;
  807.     Map *map;
  808.     
  809.     if ((map = map_from_window(FrontWindow())) != NULL) {
  810.         GetMouse(&to);
  811.         if (m_nearest_boundary(map, to.h, to.v, &x, &y, &dir)) {
  812.             tmpcmdx = x;  tmpcmdy = y;  tmpcmddir = dir;
  813.             apply_to_all_selected(do_one_remove_terrain, TRUE);
  814.             return;
  815.         }
  816.     }
  817.     beep();
  818. }
  819.  
  820. static int
  821. do_one_remove_terrain(Unit *unit)
  822. {
  823.     int u, t, dir;
  824.  
  825.     u = unit->type;
  826.     for_all_terrain_types(t) {
  827.         if (ut_acp_to_remove_terrain(u, t) > 0
  828.             && unit->act
  829.             && unit->act->acp >= ut_acp_to_remove_terrain(u, t)) {
  830.             if (distance(tmpcmdx, tmpcmdy, unit->x, unit->y) <= ut_alter_range(u, t)) {
  831.                 if (prep_remove_terrain_action(unit, unit, tmpcmdx, tmpcmdy, tmpcmddir, t))
  832.                   return TRUE;
  833.             } else {
  834.                 dir = closest_dir(tmpcmdx - unit->x, tmpcmdy - unit->y);
  835.                 if (prep_remove_terrain_action(unit, unit, unit->x, unit->y, dir, t))
  836.                   return TRUE;
  837.             }
  838.         }
  839.     }
  840.     return FALSE;
  841. }
  842.  
  843. static int
  844. do_one_reserve(Unit *unit)
  845. {
  846.     set_unit_reserve(dside, unit, tmpcmdarg, tmprecurse);
  847.     return TRUE;
  848. }
  849.  
  850. void
  851. do_reserve_command(int value, int recurse)
  852. {
  853.     tmpcmdarg = value;
  854.     tmprecurse = recurse;
  855.     apply_to_all_selected(do_one_reserve, TRUE);    
  856. }
  857.  
  858. void
  859. do_reserve()
  860. {
  861.     do_reserve_command(TRUE, FALSE);
  862. }
  863.  
  864. static int
  865. do_one_return(Unit *unit)
  866. {
  867.     if (1 /* has a place to return to */) {
  868.         set_resupply_task(unit);
  869.         return TRUE;
  870.     }
  871.     return FALSE;
  872. }
  873.  
  874. void
  875. do_return()
  876. {
  877.     apply_to_all_selected(do_one_return, TRUE);    
  878. }
  879.  
  880. void
  881. do_save()
  882. {
  883.     save_the_game(FALSE, FALSE);
  884. }
  885.  
  886. void
  887. do_set_formation()
  888. {
  889.     int i, numcould = 0, numnot = 0;
  890.     Point lead;
  891.     Map *map;
  892.     Unit *follower, *leader;
  893.     
  894.     if ((map = map_from_window(FrontWindow())) != NULL) {
  895.         GetMouse(&lead);
  896.         m_nearest_unit(map, lead.h, lead.v, &leader);
  897.         if (leader != NULL) {
  898.             for (i = 0; i < map->numselections; ++i) {
  899.                 if ((follower = map->selections[i]) != NULL && valid_selection(follower)) {
  900.                     if (leader != follower
  901.                         && leader->side == follower->side
  902.                         ) {
  903.                         set_formation(follower, leader, follower->x - leader->x, follower->y - leader->y, 1, 1);
  904.                         ++numcould;
  905.                     } else {
  906.                         ++numnot;
  907.                     }
  908.                 }
  909.             }
  910.         } else {
  911.             /* (should beep?) */
  912.         }
  913.     }
  914.     /* If nobody could do the action, beep once. */
  915.     if (numcould == 0 && numnot > 0) {
  916.         beep();
  917.     }
  918. }
  919.  
  920. static int
  921. do_one_asleep(Unit *unit)
  922. {
  923.     set_unit_asleep(dside, unit, tmpcmdarg, tmprecurse);
  924.     return TRUE;
  925. }
  926.  
  927. void
  928. do_sleep_command(int value, int recurse)
  929. {
  930.     tmpcmdarg = value;
  931.     tmprecurse = recurse;
  932.     apply_to_all_selected(do_one_asleep, TRUE);    
  933. }
  934.  
  935. void
  936. do_sleep()
  937. {
  938.     do_sleep_command(TRUE, FALSE);
  939. }
  940.  
  941. void 
  942. do_survey()
  943. {
  944.     Map *map;
  945.  
  946.     if ((map = map_from_window(FrontWindow())) != NULL) {
  947.         toggle_survey(map);
  948.     }
  949. }
  950.  
  951. void
  952. do_take()
  953. {
  954.     /* (should use argument) */
  955.     apply_to_all_selected(do_one_take, TRUE);
  956. }
  957.  
  958. void
  959. do_take_unit()
  960. {
  961.     beep();
  962. }
  963.  
  964. void
  965. do_version()
  966. {
  967.     do_about_box();
  968. }
  969.  
  970. void
  971. do_wake()
  972. {
  973.     do_sleep_command(FALSE, FALSE);
  974.     do_reserve_command(FALSE, FALSE);
  975. }
  976.  
  977. void
  978. do_wake_all()
  979. {
  980.     do_sleep_command(FALSE, TRUE);
  981.     do_reserve_command(FALSE, TRUE);
  982. }
  983.  
  984. void
  985. do_warranty()
  986. {
  987.     /* (should be a help node?) */
  988.     beep();
  989. }
  990.  
  991. #ifdef DESIGNERS
  992.  
  993. /* Toggle the designer mode. */
  994.  
  995. void
  996. do_design()
  997. {
  998.     if (!dside->designer) {
  999.         enable_designing(FALSE);
  1000.     } else {
  1001.         disable_designing();
  1002.     }
  1003. }
  1004.  
  1005. #endif
  1006.  
  1007. #ifdef DEBUGGING
  1008.  
  1009. void
  1010. do_debug()
  1011. {
  1012.     toggle_debugging(&Debug);
  1013. }
  1014.  
  1015. void
  1016. do_debugg()
  1017. {
  1018.     toggle_debugging(&DebugG);
  1019. }
  1020.  
  1021. void
  1022. do_debugm()
  1023. {
  1024.     toggle_debugging(&DebugM);
  1025. }
  1026.  
  1027. void
  1028. do_profile()
  1029. {
  1030.     toggle_debugging(&Profile);
  1031. }
  1032.  
  1033. void
  1034. do_trace()
  1035. {
  1036.     toggle_debugging(&Profile);
  1037. #ifdef PROFILING
  1038.     _trace = 1;
  1039. #endif
  1040. }
  1041.  
  1042. #endif
  1043.  
  1044. /* End of alphabetized commands. */
  1045.  
  1046. /* Mac-specific command functions. */
  1047.  
  1048. void
  1049. do_force_global_replan()
  1050. {
  1051.     force_global_replan(dside);
  1052. }
  1053.  
  1054. void
  1055. do_escape()
  1056. {
  1057.     map_modal = NO_MODAL;
  1058. }
  1059.  
  1060. void
  1061. do_set_map_angle()
  1062. {
  1063.     int angle;
  1064.     Map *map;
  1065.     extern int vertexagg;
  1066.  
  1067.     map = map_from_window(FrontWindow());
  1068.     if (map != NULL) {
  1069.         angle = map->vp->angle;
  1070.         if (angle == 90)
  1071.           angle = 30;
  1072.         else if (angle == 30)
  1073.           angle = 15;
  1074.         else
  1075.           angle = 90;
  1076.         vertexagg = (prefixarg < 1 ? 1 : prefixarg);
  1077.         set_view_angle(map->vp, angle);
  1078.         force_map_update(map);
  1079.     }
  1080. }
  1081.  
  1082. #ifdef DEBUGGING
  1083.  
  1084. /* Junk associated with debug output. */
  1085.  
  1086. /* This is all fairly elaborate because we need to be able to collect
  1087.    detailed logs of AI activity over different periods of time, and just
  1088.    dumping to stdout doesn't work in a window system. */
  1089.  
  1090. #ifdef USE_CONSOLE
  1091. #ifdef THINK_C
  1092. #include <console.h>
  1093. #endif
  1094. #endif
  1095.  
  1096. extern FILE *pfp;
  1097.  
  1098. FILE *ffp = NULL;
  1099.  
  1100. int firstdebug = TRUE;
  1101.  
  1102. void
  1103. update_debugging()
  1104. {
  1105.     if (Debug || DebugG || DebugM || Profile) {
  1106.         /* Always close the file if open, forces to desirable state. */
  1107.         if (ffp != NULL) {
  1108.             fclose(ffp);
  1109.             ffp = NULL;
  1110.         }
  1111.         /* Reopen the file. */
  1112.         if (ffp == NULL) {
  1113.             ffp = fopen("Xconq.DebugOut", "a");
  1114.         }
  1115.         if (ffp != NULL) {
  1116.             if (Debug)
  1117.               dfp = ffp;
  1118.             if (DebugG)
  1119.               dgfp = ffp;
  1120.             if (DebugM)
  1121.               dmfp = ffp;
  1122.             if (Profile)
  1123.               pfp = ffp;
  1124.         }
  1125.     }
  1126. }
  1127.  
  1128. /* Debug output goes to a file. */
  1129.  
  1130. void
  1131. toggle_debugging(int *flagp)
  1132. {
  1133. #ifdef PROFILING
  1134.     extern int _profile;
  1135. #endif
  1136.  
  1137.     /* Always close the file if open, forces to desirable state. */
  1138.     if (ffp != NULL) {
  1139.         fclose(ffp);
  1140.         ffp = NULL;
  1141.     }
  1142.     /* Flip the state of the debugging flag, if supplied. */ 
  1143.     if (flagp != NULL) {
  1144.         *flagp = ! *flagp;
  1145.     }
  1146.     /* (Re-)open the debugging transcript file. */
  1147.     if (ffp == NULL) {
  1148.         ffp = fopen("Xconq.DebugOut", (firstdebug ? "w" : "a"));
  1149.         firstdebug = FALSE;
  1150.     }
  1151.     if (flagp != NULL) {
  1152.         /* Indicate which flags are now on. */
  1153.         fprintf(ffp, "\n\n*********** %s %s %s %s **********\n\n",
  1154.                 (Debug ? "Debug" : ""), (DebugM ? "DebugM" : ""),
  1155.                 (DebugG ? "DebugG" : ""), (Profile ? "Profile" : ""));
  1156.         /* Indicate this in a window also. */
  1157.         draw_game();
  1158.     }
  1159.     /* Set specific debug file pointers to be the same as the
  1160.        pointer to the file. */
  1161.     if (ffp != NULL) {
  1162.         if (Debug) dfp = ffp;
  1163.         if (DebugG) dgfp = ffp;
  1164.         if (DebugM) dmfp = ffp;
  1165.         if (Profile) pfp = ffp;
  1166.     }
  1167. #ifdef PROFILING
  1168. #ifdef THINK_C
  1169.     if (Profile && !_profile) {
  1170.         InitProfile(1000, 100);
  1171.     }
  1172.     if (!Profile && _profile) {
  1173.         EndProfile();
  1174.     }
  1175. #endif
  1176. #endif
  1177.     /* If all debugging flags have been turned off, close the file too. */
  1178.     if (!Debug && !DebugG && !DebugM && !Profile) {
  1179.         if (ffp != NULL) {
  1180.             fclose(ffp);
  1181.             ffp = NULL;
  1182.         }
  1183.     }
  1184. }
  1185.  
  1186. #endif /* DEBUGGING */
  1187.